package datacache

import (
	"container/list"
	"context"
	"cow_golang/shared_mod/datacache/iface"
	"errors"
	"sync"
	"time"
)

type MemoryCache struct {
	mu         sync.RWMutex
	items      map[string]*cacheItem
	lruList    *list.List
	maxItems   int
	defaultTTL time.Duration
	stats      iface.CacheStats
}

type cacheItem struct {
	key        string
	value      interface{}
	expiration time.Time
	lruElement *list.Element
	indexes    map[string]map[string]struct{} // indexName -> indexKey -> struct{}
}

type indexEntry struct {
	primaryKeys map[string]struct{} // 主键集合
}

func NewMemoryCache(config iface.Config) iface.IDataCache {
	return &MemoryCache{
		items:      make(map[string]*cacheItem),
		lruList:    list.New(),
		maxItems:   config.MaxItems,
		defaultTTL: config.DefaultExpiry,
	}
}

func (c *MemoryCache) Set(ctx context.Context, key string, value interface{}, ttl time.Duration) error {
	if ttl == 0 {
		ttl = c.defaultTTL
	}

	c.mu.Lock()
	defer c.mu.Unlock()

	// 检查是否已存在
	if item, exists := c.items[key]; exists {
		// 更新值和过期时间
		item.value = value
		item.expiration = time.Now().Add(ttl)
		// 移动到LRU列表前端
		c.lruList.MoveToFront(item.lruElement)
		return nil
	}

	// 检查是否需要淘汰
	if c.maxItems > 0 && len(c.items) >= c.maxItems {
		c.evict(1)
	}

	// 创建新项
	expiration := time.Now().Add(ttl)
	element := c.lruList.PushFront(key)
	item := &cacheItem{
		key:        key,
		value:      value,
		expiration: expiration,
		lruElement: element,
		indexes:    make(map[string]map[string]struct{}),
	}

	c.items[key] = item
	return nil
}

func (c *MemoryCache) Get(ctx context.Context, key string) (interface{}, error) {
	c.mu.RLock()
	item, exists := c.items[key]
	c.mu.RUnlock()

	if !exists {
		c.mu.Lock()
		c.stats.Misses++
		c.mu.Unlock()
		return nil, nil
	}

	// 检查是否过期
	if time.Now().After(item.expiration) {
		c.mu.Lock()
		delete(c.items, key)
		c.lruList.Remove(item.lruElement)
		c.stats.Expired++
		c.stats.Misses++
		c.mu.Unlock()
		return nil, nil
	}

	c.mu.Lock()
	c.lruList.MoveToFront(item.lruElement)
	c.stats.Hits++
	c.mu.Unlock()

	return item.value, nil
}

func (c *MemoryCache) Delete(ctx context.Context, key string) error {
	c.mu.Lock()
	defer c.mu.Unlock()

	item, exists := c.items[key]
	if !exists {
		return nil
	}

	// 从LRU列表中移除
	c.lruList.Remove(item.lruElement)

	// 从主存储中移除
	delete(c.items, key)

	return nil
}

func (c *MemoryCache) Exists(ctx context.Context, key string) (bool, error) {
	c.mu.RLock()
	defer c.mu.RUnlock()

	item, exists := c.items[key]
	if !exists {
		return false, nil
	}

	if time.Now().After(item.expiration) {
		return false, nil
	}

	return true, nil
}

func (c *MemoryCache) SetWithPrimaryKey(ctx context.Context, primaryKey string, value interface{}, ttl time.Duration) error {
	return c.Set(ctx, primaryKey, value, ttl)
}

func (c *MemoryCache) GetByPrimaryKey(ctx context.Context, primaryKey string) (interface{}, error) {
	return c.Get(ctx, primaryKey)
}

func (c *MemoryCache) AddIndex(ctx context.Context, indexName string, indexKey string, primaryKey string) error {
	c.mu.Lock()
	defer c.mu.Unlock()

	item, exists := c.items[primaryKey]
	if !exists {
		return errors.New("primary key not found")
	}

	// 初始化索引map如果不存在
	if _, ok := item.indexes[indexName]; !ok {
		item.indexes[indexName] = make(map[string]struct{})
	}

	// 添加索引键
	item.indexes[indexName][indexKey] = struct{}{}
	return nil
}

func (c *MemoryCache) GetByIndex(ctx context.Context, indexName string, indexKey string) ([]interface{}, error) {
	c.mu.RLock()
	defer c.mu.RUnlock()

	var results []interface{}

	for _, item := range c.items {
		// 检查是否过期
		if time.Now().After(item.expiration) {
			continue
		}

		// 检查是否有该索引
		if indexKeys, ok := item.indexes[indexName]; ok {
			if _, hasKey := indexKeys[indexKey]; hasKey {
				results = append(results, item.value)
			}
		}
	}

	return results, nil
}

func (c *MemoryCache) RemoveIndex(ctx context.Context, indexName string, indexKey string, primaryKey string) error {
	c.mu.Lock()
	defer c.mu.Unlock()

	item, exists := c.items[primaryKey]
	if !exists {
		return nil
	}

	if indexKeys, ok := item.indexes[indexName]; ok {
		delete(indexKeys, indexKey)

		// 如果这个索引名下的所有键都删除了，删除整个索引
		if len(indexKeys) == 0 {
			delete(item.indexes, indexName)
		}
	}

	return nil
}

func (c *MemoryCache) CleanExpired(ctx context.Context) error {
	c.mu.Lock()
	defer c.mu.Unlock()

	var expiredKeys []string

	// 收集过期键
	for key, item := range c.items {
		if time.Now().After(item.expiration) {
			expiredKeys = append(expiredKeys, key)
		}
	}

	// 删除过期项
	for _, key := range expiredKeys {
		item := c.items[key]
		c.lruList.Remove(item.lruElement)
		delete(c.items, key)
		c.stats.Expired += int64(len(expiredKeys))
	}

	return nil
}

func (c *MemoryCache) Stats() iface.CacheStats {
	c.mu.RLock()
	defer c.mu.RUnlock()

	stats := c.stats
	stats.Size = int64(len(c.items))
	return stats
}

func (c *MemoryCache) evict(count int) {
	for i := 0; i < count && c.lruList.Len() > 0; i++ {
		element := c.lruList.Back()
		if element == nil {
			break
		}

		key := element.Value.(string)
		delete(c.items, key)
		c.lruList.Remove(element)
		c.stats.Evictions++
	}
}
